package com.module.admin.prj.utils;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.netflix.eureka.EurekaDiscoveryClient.EurekaServiceInstance;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import com.module.admin.cli.pojo.CliInfo;
import com.module.admin.prj.enums.PrjClientStatus;
import com.module.admin.prj.pojo.PrjClient;
import com.module.admin.prj.pojo.PrjInfo;
import com.module.admin.prj.service.PrjClientService;
import com.module.admin.prj.service.PrjInfoService;
import com.module.api.service.ApiServiceService;
import com.module.comm.utils.ClientUtil;
import com.ms.env.EnvUtil;
import com.netflix.appinfo.InstanceInfo;
import com.system.comm.utils.FrameHttpUtil;
import com.system.comm.utils.FrameSpringBeanUtil;
import com.system.comm.utils.FrameStringUtil;
import com.system.handle.model.ResponseCode;
import com.system.handle.model.ResponseFrame;

/**
 * 项目客户端工具类
 * @author yuejing
 * @date 2018年6月19日 上午9:28:30
 */
public class PrjClientUtil {

	private static final Logger LOGGER = LoggerFactory.getLogger(PrjClientUtil.class);

	/**
	 * 发布项目到客户端
	 * @param pi
	 * @param clients
	 * @return
	 */
	private static ResponseFrame release(PrjInfo pi, List<CliInfo> clients) {
		ResponseFrame frame = new ResponseFrame();
		ThreadPoolTaskExecutor threadPoolTaskExecutor = FrameSpringBeanUtil.getBean(ThreadPoolTaskExecutor.class);
		threadPoolTaskExecutor.execute(new Runnable() {
			@Override
			public void run() {
				PrjClientService prjClientService = FrameSpringBeanUtil.getBean(PrjClientService.class);
				ApiServiceService apiServiceService = FrameSpringBeanUtil.getBean(ApiServiceService.class);
				StringBuffer errorBuffer = new StringBuffer();
				List<String> ecUrls = FrameStringUtil.toArray(EnvUtil.eurekaClientServiceurlDefaultzone(), ",");
				for (CliInfo cliInfo : clients) {
					if (PrjClientStatus.STOP.getCode() == cliInfo.getPcStatus()) {
						// 暂停的服务不发布
						continue;
					}
					// 向注册中心剔除服务
					String healthCheckUrl = null;
					List<ServiceInstance> siList = apiServiceService.serviceList(pi.getCode());
					if (siList.size() > 0) {
						// 注册中心存在服务则执行剔除
						for (ServiceInstance si : siList) {
							if (cliInfo.getIp().equals(si.getHost())) {
								for (String ecUrl : ecUrls) {
									EurekaServiceInstance eurekaInfo = (EurekaServiceInstance) si;
									InstanceInfo info = eurekaInfo.getInstanceInfo();
									String url = ecUrl + "apps/" + si.getServiceId() + "/" + info.getInstanceId();
									try {
										// 移除注册中心的服务项
										FrameHttpUtil.delete(url);
										healthCheckUrl = si.getUri().toString();
									} catch (IOException e) {
										LOGGER.error("剔除服务[" + info.getInstanceId() + "]异常: " + e.getMessage(), e);
									}
								}
								break;
							}
						}
					}
					Map<String, Object> paramsMap = new HashMap<String, Object>();
					paramsMap.put("prjId", pi.getPrjId());
					paramsMap.put("code", pi.getCode());
					paramsMap.put("name", pi.getName());
					paramsMap.put("version", cliInfo.getVersion());
					paramsMap.put("isFirstDeploy", cliInfo.getIsFirstDeploy());
					//下载路径
					paramsMap.put("pathUrl", cliInfo.getPathUrl());
					//容器类型
					paramsMap.put("container", pi.getContainer());
					//执行的shell命令
					if (cliInfo.getIsFirstDeploy() == null || cliInfo.getIsFirstDeploy() == 0) {
						if(FrameStringUtil.isNotEmpty(cliInfo.getShellScript())) {
							paramsMap.put("shellScript", cliInfo.getShellScript());
						} else {
							paramsMap.put("shellScript", pi.getShellScript());
						}
					} else {
						// 设置首次部署的脚本
						StringBuffer shellScript = new StringBuffer();
						String rootDir = pi.getRootDir();
						shellScript.append("rm -rf ").append(rootDir).append("[prj.name]\n")
						.append("cp [prj.path][prj.name] ").append(rootDir).append("\n")
						//.append("sleep 5s").append("\n")
						// -o 使解压时不必先询问用户，unzip执行后覆盖原有文件
						.append("unzip -o ").append(rootDir).append("[prj.name] -d ").append(rootDir).append("\n")
						//.append("sleep 10s").append("\n")
						.append("chmod +x ").append(rootDir).append(pi.getCode()).append("/bin/*\n")
						.append("sh ").append(rootDir).append(pi.getCode()).append("/bin/start.sh");
						paramsMap.put("shellScript", shellScript.toString());
					}
					//校验服务是否启动的地址
					paramsMap.put("healthCheckUrl", healthCheckUrl);
					ResponseFrame clientFrame = ClientUtil.post(cliInfo.getClientId(), cliInfo.getToken(), cliInfo.getIp(), cliInfo.getPort(),
							"/project/release", paramsMap);
					if(ResponseCode.SUCC.getCode() == clientFrame.getCode().intValue()) {
						//修改为发布中
						prjClientService.updateStatus(cliInfo.getClientId(), pi.getPrjId(), cliInfo.getVersion(), PrjClientStatus.ING.getCode(), null);
						if (FrameStringUtil.isNotEmpty(healthCheckUrl)) {
							int num = 0;
							while (true) {
								num ++;
								try {
									Thread.sleep(15000);
								} catch (InterruptedException e) {
								}
								PrjClient org = prjClientService.get(pi.getPrjId(), cliInfo.getVersion(), cliInfo.getClientId());
								if (org != null && org.getStatus() != PrjClientStatus.ING.getCode()) {
									LOGGER.info(healthCheckUrl + "第" + num + "次校验成功。");
									break;
								}
								LOGGER.info(healthCheckUrl + "第" + num + "次校验失败。");
								if (num > 10) {
									LOGGER.info(healthCheckUrl + "等待校验服务时间超时，结束校验线程。");
									break;
								}
							}
						}
					} else {
						//处理发布不成功的情况
						errorBuffer.append(clientFrame.getMessage());
						String msg = "无法访问[" + cliInfo.getIp() + ":" + cliInfo.getPort() + "]，可能网络不通";
						prjClientService.updateStatus(cliInfo.getClientId(), pi.getPrjId(), cliInfo.getVersion(),
								PrjClientStatus.FAIL.getCode(), msg);
						LOGGER.info(msg);
					}
				}
			}
		});
		frame.setSucc();
		frame.setMessage("任务提交成功");
		return frame;
	}

	/**
	 * 发布项目到所有客户端
	 * @param pi
	 * @param version
	 * @return
	 */
	public static ResponseFrame releaseAll(Integer prjId, String version) {
		PrjClientService prjClientService = FrameSpringBeanUtil.getBean(PrjClientService.class);
		PrjInfoService prjInfoService = FrameSpringBeanUtil.getBean(PrjInfoService.class);
		PrjInfo pi = prjInfoService.get(prjId);
		List<CliInfo> clients = prjClientService.findByPrjId(pi.getPrjId(), version, null);
		return release(pi, clients);
	}

	/**
	 * 发布到单个客户端
	 * @param prjId
	 * @param version
	 * @param clientId
	 * @return
	 */
	public static ResponseFrame releaseSingle(Integer prjId, String version, String clientId) {
		PrjClientService prjClientService = FrameSpringBeanUtil.getBean(PrjClientService.class);
		PrjInfoService prjInfoService = FrameSpringBeanUtil.getBean(PrjInfoService.class);
		PrjInfo pi = prjInfoService.get(prjId);
		List<CliInfo> clients = prjClientService.findByPrjId(pi.getPrjId(), version, clientId);
		return release(pi, clients);
	}

	/**
	 * 到客户端停止服务
	 * @param prjId
	 * @param version
	 * @param clientId
	 * @return
	 */
	public static ResponseFrame stopService(Integer prjId, String version, String clientId) {
		PrjClientService prjClientService = FrameSpringBeanUtil.getBean(PrjClientService.class);
		PrjInfoService prjInfoService = FrameSpringBeanUtil.getBean(PrjInfoService.class);
		ResponseFrame frame = new ResponseFrame();
		List<CliInfo> clients = prjClientService.findByPrjId(prjId, version, clientId);
		if (clients.size() == 0) {
			frame.setCode(-2);
			frame.setMessage("没有找到执行的客户端信息。");
			return frame;
		}
		PrjInfo pi = prjInfoService.get(prjId);
		CliInfo cliInfo = clients.get(0);
		Map<String, Object> paramsMap = new HashMap<String, Object>();
		paramsMap.put("type", "stop");
		paramsMap.put("prjId", pi.getPrjId());
		paramsMap.put("prjName", pi.getName());
		paramsMap.put("version", cliInfo.getVersion());
		//容器类型
		paramsMap.put("container", pi.getContainer());
		//执行的stop命令
		if(FrameStringUtil.isNotEmpty(cliInfo.getStopScript())) {
			paramsMap.put("shellScript", cliInfo.getStopScript());
		} else {
			paramsMap.put("shellScript", pi.getStopScript());
		}
		ResponseFrame clientFrame = ClientUtil.post(cliInfo.getClientId(), cliInfo.getToken(), cliInfo.getIp(), cliInfo.getPort(),
				"/project/execShell", paramsMap);

		return clientFrame;
	}
	/**
	 * 到客户端重启服务
	 * @param prjId
	 * @param version
	 * @param clientId
	 * @return
	 */
	public static ResponseFrame restartService(Integer prjId, String version, String clientId) {
		PrjClientService prjClientService = FrameSpringBeanUtil.getBean(PrjClientService.class);
		PrjInfoService prjInfoService = FrameSpringBeanUtil.getBean(PrjInfoService.class);
		ResponseFrame frame = new ResponseFrame();
		List<CliInfo> clients = prjClientService.findByPrjId(prjId, version, clientId);
		if (clients.size() == 0) {
			frame.setCode(-2);
			frame.setMessage("没有找到执行的客户端信息。");
			return frame;
		}
		PrjInfo pi = prjInfoService.get(prjId);
		CliInfo cliInfo = clients.get(0);
		Map<String, Object> paramsMap = new HashMap<String, Object>();
		paramsMap.put("type", "restart");
		paramsMap.put("prjId", pi.getPrjId());
		paramsMap.put("prjName", pi.getName());
		paramsMap.put("version", cliInfo.getVersion());
		//容器类型
		paramsMap.put("container", pi.getContainer());
		//执行的stop命令
		if(FrameStringUtil.isNotEmpty(cliInfo.getRestartScript())) {
			paramsMap.put("shellScript", cliInfo.getRestartScript());
		} else {
			paramsMap.put("shellScript", pi.getRestartScript());
		}
		ResponseFrame clientFrame = ClientUtil.post(cliInfo.getClientId(), cliInfo.getToken(), cliInfo.getIp(), cliInfo.getPort(),
				"/project/execShell", paramsMap);
		return clientFrame;
	}
}